﻿using Dm.util;
using JinianNet.JNTemplate;
using Microsoft.Extensions.Options;
using RuoVea.CodeGen.Server.Util;
using RuoVea.ExEnum;
using RuoVea.ExIdGen;
using RuoVea.ExSugar;
using RuoVea.ExUtil;
using RuoVea.ExUtil.Exceptions;
using System.IO.Compression;
using System.Text;

namespace RuoVea.CodeGen.Web.Controllers;

/// <summary>
/// 
/// </summary>
public partial class DbTableMetadataController : Controller
{
    /// <summary>
    /// 
    /// </summary>
    private readonly SugarRepository<GenDbTableMetadata> _thisRepository;
    private readonly List<DbConnectionConfig> _dbConnectionConfigs;
    private readonly ISqlSugarClient _defultDbContext;

    /// <summary>
    /// 
    /// </summary>
    /// <param name="thisRepository"></param> 
    /// <param name="dbConnectionConfigs"></param> 
    public DbTableMetadataController(SugarRepository<GenDbTableMetadata> thisRepository, IOptions<List<DbConnectionConfig>> dbConnectionConfigs, ISqlSugarClient defultDbContext)
    {
        _thisRepository = thisRepository;
        _dbConnectionConfigs = dbConnectionConfigs.Value;
        _defultDbContext = defultDbContext;
    }


    public IActionResult Index()
    {
        return View();
    }

    /// <summary>
    /// 查询所有/分页
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    [HttpPost("/TableMetadata/pages")]
    public async Task<RestfulResult<PageResult<GenDbTableMetadata>>> GetPagesAsync()
    {
        using var sr = new StreamReader(Request.Body);
        string dataStr = await sr.ReadToEndAsync();
        if (Request.Body.CanSeek)
            Request.Body.Position = 0;
        if (string.IsNullOrWhiteSpace(dataStr))
            throw new Exception("未提供上传数据。请在Request.Body中携带上传数据。");
        PageParam? data = JsonConvert.DeserializeObject<PageParam>(dataStr);
        data ??= new PageParam { PageNo = 1, PageSize = 10 };

        var restful = new RestfulResult<PageResult<GenDbTableMetadata>>() { Code = CodeStatus.OK };
        data ??= new PageParam { PageNo = 1, PageSize = 10 };
        var query = await _thisRepository.AsQueryable()
            .ToPageAsync(data.PageNo, data.PageSize);

        restful.Data = query;
        return restful;
    }

    /// <summary>
    /// 查询所有/分页
    /// </summary>
    /// <returns></returns>
    [HttpGet("/TableMetadata/list")]
    public async Task<RestfulResult<PageResult<GenDbTableMetadata>>> GetlistAsync()
    {
        var restful = new RestfulResult<PageResult<GenDbTableMetadata>>() { Code = CodeStatus.OK };
        PageParam data = new PageParam { PageNo = 1, PageSize = 100 };
        var query = await _thisRepository.AsQueryable()
            .ToPageAsync(data.PageNo, data.PageSize);
        restful.Data = query;
        return restful;
    }

    [HttpGet("/TableMetadata/TableDatas")]
    public RestfulResult<List<DbTableInfo>> TableDatas(long dbId)
    {
        var restful = new RestfulResult<List<DbTableInfo>>() { Code = CodeStatus.OK };
        restful.Data = GetNewSqlSugarScope(dbId).DbMaintenance.GetTableInfoList();
        return restful;
    }

    private ISqlSugarClient GetNewSqlSugarScope(long dbId)
    {
        if (dbId == 0) return _defultDbContext;
        GenDbConnString dbConnStrInfo = _defultDbContext.Queryable<GenDbConnString>().Where(x => x.Id == dbId).First();
        SqlSugarScope sqlSugarScope = _defultDbContext.GetDbClient(dbId, dbConnStrInfo.ConnectionStrings, (DbType)dbConnStrInfo.DbType);
        return sqlSugarScope;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="dbId"></param>
    /// <param name="dbTableInfos"></param>
    /// <returns></returns>
    /// <exception cref="ParamiterException"></exception>
    [HttpPost("/TableMetadata/InitMetadataData")]
    public async Task InitMetadataData([FromBody] InitMetadataRequest request)
    {
        var tableNames = request.dbTableInfos.Select(c => c.Name).ToList();
        var existingTableNames = _thisRepository.AsQueryable().Where(x => tableNames.Contains(x.TableName)).Select(x => x.TableName).ToList();
        if (existingTableNames.Any())
        {
            throw new ParamiterException($"以下表名已经存在: {string.Join(", ", existingTableNames)}.");
        }
        var defultDbContext = GetNewSqlSugarScope(request.dbId);

        //if (request.dbId <= 0)
        //    throw new ParamiterException($"{{dbId}} 不存在这样的数据库配置.");
        foreach (var t in request.dbTableInfos)
        {
            string tableName = t.Name;
            if (!defultDbContext.DbMaintenance.IsAnyTable(tableName))
                throw new ParamiterException($"{{tableName}} 不存在这样的表.");

            if (!defultDbContext.DbMaintenance.IsAnyTable(nameof(GenDbTableMetadata)))
                defultDbContext.CodeFirst.InitTables(typeof(GenDbTableMetadata));

            if (!defultDbContext.DbMaintenance.IsAnyTable(nameof(GenFieldMetadata)))
                defultDbContext.CodeFirst.InitTables(typeof(GenFieldMetadata));

            // 获取表结构
            List<DbColumnInfo> columns = defultDbContext.DbMaintenance.GetColumnInfosByTableName(tableName);

            DbColumnInfo columnOne = columns.FirstOrDefault()!;

            GenDbTableMetadata tableMetadata = new GenDbTableMetadata()
            {
                DbId = request.dbId,
                TableName = columnOne.TableName,
                ClassName = columnOne.TableName,
                Id = IdGenerator.Id,
                Description = t.Description
            };

            List<GenFieldMetadata> fieldMetadatas = new List<GenFieldMetadata>();
            List<GenFieldMetadataExAvue> fieldMetadataExAvues = new List<GenFieldMetadataExAvue>();

            var properties = typeof(IPrimaryKeyEntity).GetProperties().Select(x => x.Name.ToLower()).ToList();
            //properties.AddRange(typeof(IDeletedEntity).GetProperties().Select(x => x.Name.ToLower()).ToList());
            //properties.AddRange(typeof(IAuditableEntity).GetProperties().Select(x => x.Name.ToLower()).ToList());

            foreach (DbColumnInfo column in columns)
            {
                GenFieldMetadata fieldMetadata = new GenFieldMetadata();

                fieldMetadata.TableMetaId = tableMetadata.Id;

                fieldMetadata.DbColumnName = column.DbColumnName;
                //fieldMetadata.ClassName = CodeGenUtil.CamelColumnName( column.DbColumnName,null);

                fieldMetadata.PropertyType = CodeGenUtil.ConvertDataType(column, DbType.Sqlite);
                fieldMetadata.DataType = column.DataType;
                fieldMetadata.Length = column.Length;
                fieldMetadata.Description = column.ColumnDescription;

                fieldMetadata.DefaultValue = column.DefaultValue;
                fieldMetadata.IsNullable = column.IsNullable;
                fieldMetadata.IsPrimaryKey = column.IsPrimarykey;

                fieldMetadata.IsIdentity = column.IsIdentity;
                fieldMetadata.FieldSort = column.CreateTableFieldSort;

                fieldMetadata.PropertyName = column.DbColumnName;
                fieldMetadata.DecimalDigits = column.DecimalDigits;
                fieldMetadata.IsJson = column.IsJson;
                fieldMetadata.IsIgnore = false;

                fieldMetadata.Id = IdGenerator.Id;

                fieldMetadatas.Add(fieldMetadata);


                GenFieldMetadataExAvue fieldMetadataExAvue = new GenFieldMetadataExAvue
                {
                    Id = IdGenerator.Id,
                    TableMetaId = tableMetadata.Id,
                    FieldMetadataId = fieldMetadata.Id
                };
                fieldMetadataExAvues.Add(fieldMetadataExAvue);
            }

            try
            {
                await _defultDbContext.Ado.BeginTranAsync();
                await _defultDbContext.Insertable(tableMetadata).ExecuteCommandAsync();
                await _defultDbContext.Insertable(fieldMetadatas).ExecuteCommandAsync();
                await _defultDbContext.Insertable(fieldMetadataExAvues).ExecuteCommandAsync();
                await _defultDbContext.Ado.CommitTranAsync();
            }
            catch (Exception ex)
            {
                await _defultDbContext.Ado.RollbackTranAsync();
                new ParamiterException("初始化元数据表和数据异常.", ex);
            }
        }
    }
    /// <summary>
    /// 增加
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    [UnitOfWork]
    [HttpPost("/TableMetadata/add")]
    public async Task<RestfulResult> AddAsync([FromBody] GenDbTableMetadata data)
    {
        RestfulResult restful = new() { Code = CodeStatus.BadRequest };
        bool result = await _thisRepository.InsertAsync(data);
        if (result)
        {
            restful.Data = result;
            restful.Code = CodeStatus.OK;
            return restful;
        }
        else
        {
            restful.Message = "添加失败";
            return restful;
        }
    }

    /// <summary>
    /// 更新
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    [HttpPost("/TableMetadata/update")]
    public async Task<RestfulResult> UpdateAsync([FromBody] GenDbTableMetadata data)
    {
        RestfulResult restful = new() { Code = CodeStatus.BadRequest };
        bool result = await _thisRepository.UpdateAsync(data, true, true, "笔记修改");
        if (result)
        {
            restful.Data = result;
            restful.Code = CodeStatus.OK;
            return restful;
        }
        else
        {
            restful.Message = "修改失败";
            return restful;
        }
    }

    /// <summary>
    /// 删除
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    [HttpDelete("/TableMetadata/delete")]
    public async Task<RestfulResult> DeleteAsync([FromBody] EntityBaseId data)
    {
        RestfulResult restful = new() { Code = CodeStatus.BadRequest };

        if (data.Id == 0)
        {
            restful.Message = "删除失败";
            return restful;
        }

        try
        {
            await _defultDbContext.Ado.BeginTranAsync();

            bool isDelete = await _thisRepository.DeleteByIdAsync(data.Id);
            isDelete = _thisRepository.Change<GenFieldMetadata>().Delete(x => x.TableMetaId == data.Id);
            isDelete = _thisRepository.Change<GenFieldMetadataExAvue>().Delete(x => x.TableMetaId == data.Id);
            await _defultDbContext.Ado.CommitTranAsync();
            if (isDelete)
            {
                restful.Data = isDelete;
                restful.Message = "删除成功";
                restful.Code = CodeStatus.OK;
                return restful;
            }
            else
            {
                restful.Data = isDelete;
                restful.Message = "删除失败";
                return restful;
            }
        }
        catch (Exception ex)
        {
            await _defultDbContext.Ado.RollbackTranAsync();
            restful.Data = false;
            restful.Message = "删除失败" + ex.Message;
            return restful;
        }
    }


    #region CodeBuild
    /// <summary>
    /// CodeBuild
    /// </summary>
    /// <param name="request"></param>
    /// <returns></returns>
    [HttpPost("/TableMetadata/codeBuild")]
    public RestfulResult CodeBuild([FromBody] CodeBuildRequest request)
    {
        RestfulResult restful = new() { Code = CodeStatus.OK };
        try
        {
            GenDbTableMetadata dbTableMetadata = _thisRepository.AsQueryable()
                .Where(x => x.TableName == request.TableName && x.DbId == request.ConfigId)
                .Includes(x => x.Propertys).First();

            dbTableMetadata.Description = dbTableMetadata.Description ?? dbTableMetadata.ClassName;
            // 获取表结构
            var fileTemplate = _thisRepository.Change<GenFileTemplate>().AsQueryable().Where(x => x.Id == request.TemplateId).First();
            //// 加载模板
            var template = JNTemplateEx.CreateTemplate(fileTemplate.Name, fileTemplate.Content);

            // 设置模板变量
            template.Set("Model", dbTableMetadata);

            // 渲染模板
            var result = template.Render();
            template.Context.Cache.Clear();
            restful.Data = result;
        }
        catch (Exception ex)
        {
            restful.Message = ex.Message;
            restful.Code = CodeStatus.BadRequest;
        }
        return restful;
    }
    #endregion

    #region CodeBuildByTemp
    /// <summary>
    /// CodeBuildByTemp（使用临时目录版本）
    /// </summary>
    /// <param name="request"></param>
    /// <returns></returns>
    [HttpPost("/TableMetadata/codeBuildByTemp")]
    public IActionResult CodeBuildByTemp([FromBody] CodeBuildByRequest request)
    {
        try
        {
            List<DownloadFile> downloadFiles = new();
            foreach (var item in request.TableInfos)
            {
                var result = GetContent(request.Id, item.DbId, item.TableName);
                downloadFiles.Add(result);
            }
            return DownloadFiles(request.Id.ToString(), downloadFiles);
        }
        catch (Exception ex)
        {
            return BadRequest(new RestfulResult { Code= CodeStatus.BadRequest, Message = ex.Message });
        }
    }
    #endregion

    #region CodeBuildByProject
    /// <summary>
    /// CodeBuildByProject
    /// </summary>
    /// <param name="request"></param>
    /// <returns></returns>
    [HttpPost("/TableMetadata/codeBuildByProject")]
    public IActionResult CodeBuildByProject([FromBody] CodeBuildByRequest request)
    {
        try
        {
            List<DownloadFile> downloadFiles = new();
            var projectInfo = _thisRepository.Change<GenProjectInfo>().AsQueryable().Where(x => x.Id == request.Id).First();
            foreach (var templateId in projectInfo.TemplateContent)
            {
                foreach (var item in request.TableInfos)
                {
                    var result = GetContent(templateId, item.DbId, item.TableName, projectInfo.Code);
                    downloadFiles.Add(result);
                }
            }
            return DownloadFiles(request.Id.ToString(), downloadFiles);
        }
        catch (Exception ex)
        {
            return BadRequest(new RestfulResult { Code = CodeStatus.BadRequest, Message = ex.Message });
        }
    }
    #endregion

    /// <summary>
    /// 获取生成的文件内容（使用临时目录）
    /// </summary>
    /// <param name="templateId"></param>
    /// <param name="configId"></param>
    /// <param name="tableName"></param>
    /// <param name="project"></param>
    /// <returns></returns>
    private DownloadFile GetContent(long templateId, long configId, string tableName, string project = null)
    {
        DownloadFile downloadFile = new();
        GenDbTableMetadata dbTableMetadata = _thisRepository.AsQueryable()
                    .Where(x => x.TableName == tableName && x.DbId == configId)
                    .Includes(x => x.Propertys).First();
        dbTableMetadata.Description = dbTableMetadata.Description ?? dbTableMetadata.ClassName;
        project = project ?? dbTableMetadata.NameSpace;
        dbTableMetadata.NameSpace = project;

        // 获取表结构
        var fileTemplate = _thisRepository.Change<GenFileTemplate>().AsQueryable().Where(x => x.Id == templateId).First();

        // 加载模板
        var template = JNTemplateEx.CreateTemplate(fileTemplate.Name, fileTemplate.Content);

        // 设置模板变量
        template.Set("Model", dbTableMetadata);
        // 处理构建路径，使用临时目录
        fileTemplate.BuildPath = fileTemplate.BuildPath.Replace("{project}", project);
        fileTemplate.BuildPath = string.Format(fileTemplate.BuildPath, dbTableMetadata.ClassName);

        // 使用系统临时目录作为基础路径
        string tempBasePath = Path.Combine(Path.GetTempPath(), "CodeGen");

        // 构建完整的临时文件路径
        string fullTempPath = Path.Combine(tempBasePath, fileTemplate.BuildPath.TrimStart('\\', '/'));

        // 提取文件名（带扩展名）
        downloadFile.FileNameWithExtension = Path.GetFileName(fullTempPath);

        // 提取目录路径（相对于临时基目录的相对路径）
        downloadFile.DirectoryPath = Path.GetDirectoryName(fullTempPath);

        // 保存完整的临时路径用于后续文件操作
        downloadFile.FullTempPath = fullTempPath;

        // 渲染模板
        downloadFile.Content = template.Render();
        template.Context.Cache.Clear();
        return downloadFile;
    }

    /// <summary>
    /// 下载文件（使用临时目录）
    /// </summary>
    /// <param name="fileName"></param>
    /// <param name="downloadFiles"></param>
    /// <returns></returns>
    private IActionResult DownloadFiles(string fileName, List<DownloadFile> downloadFiles)
    {
        string tempBasePath = Path.GetTempPath();
        List<string> tempFoldersToDelete = new List<string>();

        try
        {
            // 创建所有文件到临时目录
            foreach (DownloadFile file in downloadFiles)
            {
                // 确保目录存在
                if (!Directory.Exists(file.DirectoryPath))
                    Directory.CreateDirectory(file.DirectoryPath);

                // 写入文件内容
                System.IO.File.WriteAllText(file.FullTempPath, file.Content, Encoding.UTF8);

                // 记录需要清理的临时文件夹（去重）
                var parentTempDir = Path.GetDirectoryName(file.DirectoryPath);
                if (!tempFoldersToDelete.Contains(parentTempDir))
                    tempFoldersToDelete.Add(parentTempDir);
            }

            // 创建内存流存放ZIP文件
            var memoryStream = new MemoryStream();

            // 创建ZIP文件
            using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
            {
                // 添加文件到ZIP
                foreach (DownloadFile file in downloadFiles)
                {
                    // 计算ZIP中的相对路径
                    string relativePath = file.FullTempPath.Substring(tempBasePath.Length).TrimStart('\\', '/');
                    var entry = archive.CreateEntry(relativePath);

                    using (var entryStream = entry.Open())
                    using (var fileStream = System.IO.File.OpenRead(file.FullTempPath))
                    {
                        fileStream.CopyTo(entryStream);
                    }
                }
            }

            // 重置流位置
            memoryStream.Seek(0, SeekOrigin.Begin);

            // 返回ZIP文件
            return File(memoryStream, "application/zip", $"{fileName}_{DateTime.Now:yyyyMMddHHmmss}.zip");
        }
        finally
        {
            // 清理临时文件
            foreach (var tempFolder in tempFoldersToDelete.Distinct())
            {
                try
                {
                    if (Directory.Exists(tempFolder))
                    {
                        Directory.Delete(tempFolder, true);
                    }
                }
                catch
                {
                    // 清理失败时忽略，系统会在适当时候自动清理临时文件
                }
            }
        }
    }
}